import * as step from '@flow-step/step-toolkit'
import child_process, {execSync} from "child_process";
import {dirname, isAbsolute, join} from "path";

export function checkDockerInstallation(): boolean {
    // fix docker: command not found bug on darwin
    if (step.platform.PLATFORM_DARWIN === step.platform.getPlatform()) {
        step.addPath("/usr/local/bin")
    }

    try {
        const result = child_process.execSync('docker --version').toString();
        step.info(`Docker client is installed: ${result}`)
    } catch (error) {
        step.error(`Docker client is not installed: ${error}`);
        return false;
    }

    try {
        const result = child_process.execSync('docker buildx version').toString();
        step.debug(`docker buildx version: ${result}`)
        // docker-ce
        // linux github.com/docker/buildx v0.14.0 171fcbe
        // darwin github.com/docker/buildx v0.12.0-desktop.2 c5a13b51c1ae9358eb691e9a21c955590e26d0a0
        if (result.includes('github.com/docker/buildx')) {
            return true
        }

        step.info(`docker buildx version: ${result}`)
        step.error("please install docker-ce version >= 19.03 to support docker buildx")
        return false;
    } catch (error) {
        step.error(`docker buildx version: ${error}`)
        return false;
    }
}

export async function waitDockerDaemonReady(maxAttempts = 100) {
    if (step.platform.PLATFORM_WIN === step.platform.getPlatform()) {
        throw new Error(`Docker build is currently not supported on Windows.`);
    }

    let attempt = 0;
    let ready = false;
    while (!ready && attempt < maxAttempts) {
        attempt++;
        try {
            let command = 'docker info > /dev/null 2>&1';
            if (step.platform.PLATFORM_WIN === step.platform.getPlatform()) {
                command = 'docker info > $null 2>&1'
            }
            execSync(command);
            ready = true;
        } catch (error) {
            if (attempt < maxAttempts) {
                step.info('Docker daemon not ready, waiting...');
                await sleep(200);
            } else {
                throw new Error(`Failed to connect to Docker daemon after ${maxAttempts} attempts with err: ${error}.`);
            }
        }
    }
    step.info('Docker daemon is ready');
}

function sleep(ms: number) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

export function createDockerBuildxBuilder() {
    try {
        let command = 'docker buildx inspect flow-build-container > /dev/null 2>&1';
        if (step.platform.PLATFORM_WIN === step.platform.getPlatform()) {
            command = 'docker buildx inspect flow-build-container > $null 2>&1'
        }
        execSync(command);
        step.info(`Docker buildx builder is installed`);
    } catch (error) {
        step.info('Docker buildx builder not installed, installing...');

        let image = 'build-steps-public-registry.cn-beijing.cr.aliyuncs.com/build-steps/docker@sha256:c3cb08891c15763d426ba017fa7ce957537a779837f5bf2f7b50de3796e13918'
        let arch: string = step.platform.getArch()
        if (arch === 'arm64') {
            image = "build-steps-public-registry.cn-beijing.cr.aliyuncs.com/build-steps/docker@sha256:957eb319e91a8f4da122e988fc54632c929c94085ec0590ff47c77ad29a8e33f"
        }
        execSync(`docker buildx create --name flow-build-container --use --bootstrap --driver=docker-container --driver-opt=image=${image},network=host`);
        step.info('Docker buildx builder installed successfully');
    }
}

export function formatContextPath(contextPath: string | undefined, dockerfilePath: string, projectDir: string): string {
    // contextPath 不为空，拼接 projectDir 与 contextPath
    if (!!contextPath) {
        return join(projectDir, contextPath);
    }

    // 以下为 contextPath 为空的情况
    // dockerfilePath 是绝对路径
    if (isAbsolute(dockerfilePath)) {
        return dirname(dockerfilePath);
    }

    // dockerfilePath 不包含路径
    if (!dockerfilePath.includes('/')) {
        return projectDir;
    }

    // dockerfilePath 包含文件路径，且本身非绝对路径
    return join(projectDir, dirname(dockerfilePath));
}

export function formatDate(date: Date): string {
    const year = date.getFullYear().toString();
    const month = (date.getMonth() + 1).toString().padStart(2, '0');
    const day = date.getDate().toString().padStart(2, '0');
    const hours = date.getHours().toString().padStart(2, '0');
    const minutes = date.getMinutes().toString().padStart(2, '0');
    const seconds = date.getSeconds().toString().padStart(2, '0');

    return `${year}-${month}-${day}-${hours}-${minutes}-${seconds}`;
}

export function getImageRepositoryFromImageId(imageId: string): string {
    const lastColonIndex = imageId.lastIndexOf(':');
    const lastSlashIndex = imageId.lastIndexOf('/');

    // 检查是否存在 ':' 并且 ':' 在最后一个 '/' 之后
    if (lastColonIndex != -1 && lastColonIndex > lastSlashIndex) {
        return imageId.substring(0, lastColonIndex);
    }

    // 没有 tag，返回原字符串
    return imageId;
}

export function getTagFromImageId(imageId: string): string {
    const parts = imageId.split(':');
    switch (parts.length) {
        case 2:
            if (parts[1].includes('/')) {
                return "";
            }
            return parts[1];
        case 3:
            return parts[2];
        default:
            return "";
    }
}

export function parseImage(image: string) {
    const TIMESTAMP: number = Math.floor(Date.now() / 1000);
    const DATETIME: string = formatDate(new Date());
    image = image.replace(/\$\{TIMESTAMP}/g, TIMESTAMP.toString());
    return image.replace(/\$\{DATETIME}/g, DATETIME);
}


export function convertToVpcImage(image: string): string {
    const parts = image.split('/');
    if (parts.length > 0) {
        const firstPart = parts[0];
        if (firstPart.endsWith('aliyuncs.com')) {
            const domainParts = firstPart.split('.');
            if (domainParts.length > 1 && !domainParts[0].includes('-vpc')) {
                domainParts[0] += '-vpc';
                parts[0] = domainParts.join('.');
                return parts.join('/');
            }
        }
    }

    return image;
}

export function getDockerBuildArgs(image: string, targetDockerfilePath: string, contextPath: string, cacheType: string, cacheImageId: string) {
    let args = ['buildx', 'build', '--progress=plain', '-t', image, '-f', targetDockerfilePath, contextPath, "--push"];

    if (cacheType === 'no-cache') {
        args.push('--no-cache')
    } else if (cacheType === 'remote') {
        // 本地缓存不需要传递参数,远程缓存需要追加 --cache-from --cache-to
        if (cacheImageId !== undefined && cacheImageId !== "") {
            cacheImageId = cacheImageId as string
        } else {
            const imageRepository = getImageRepositoryFromImageId(image)
            cacheImageId = imageRepository + ":flow-docker-build-cache"
        }

        args.push('--cache-from', cacheImageId)
        args.push('--cache-to', cacheImageId)
    }

    return args;
}